/*
 * @(#)DependencyFigure.java
 *
 * Copyright (c) 1996-2010 by the original authors of JHotDraw and all its
 * contributors. All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the 
 * license agreement you entered into with the copyright holders. For details
 * see accompanying license terms.
 */
package stateDiagram.figures;

import org.jhotdraw.draw.connector.Connector;
import org.jhotdraw.draw.decoration.ArrowTip;
import org.jhotdraw.draw.layouter.HorizontalLayouter;
import org.jhotdraw.draw.layouter.LocatorLayouter;
import org.jhotdraw.draw.layouter.VerticalLayouter;
import org.jhotdraw.draw.liner.ElbowLiner;
import org.jhotdraw.draw.locator.RelativeLocator;

import java.awt.*;
import java.io.IOException;

import static org.jhotdraw.draw.AttributeKeys.*;
import org.jhotdraw.draw.*;
import org.jhotdraw.geom.Insets2D;
import org.jhotdraw.xml.DOMInput;
import org.jhotdraw.xml.DOMOutput;

import stateDiagram.EntityObjects.TransitionEntity;

/**
 * DependencyFigure.
 *
 * @author Werner Randelshofer.
 * @version $Id: DependencyFigure.java 718 2010-11-21 17:49:53Z rawcoder $
 */
public class TransitionFigure extends LabeledLineConnectionFigure {
	private TransitionEntity transitionEntity;
	private TransitionEventTextFigure eventName;
	private TransitionActionTextFigure actionName;

    /** Creates a new instance. */
    public TransitionFigure() {
    	
    	setLiner(new ElbowLiner());
    	  transitionEntity = new TransitionEntity("Event",this);
        set(STROKE_COLOR, new Color(0x000099));
        set(STROKE_WIDTH, 1d);
        set(END_DECORATION, new ArrowTip());
        
        set(COMPOSITE_ALIGNMENT, Alignment.CENTER);
        setAttributeEnabled(END_DECORATION, false);
        setAttributeEnabled(START_DECORATION, false);
        setAttributeEnabled(STROKE_DASHES, false);
        setAttributeEnabled(FONT_ITALIC, false);
        setAttributeEnabled(FONT_UNDERLINE, false);
        eventName = new TransitionEventTextFigure("Event", this.getTransitionEntity()); 
        eventName.setText("Event");
        eventName.setEditable(true);
        LabelFigure slash = new LabelFigure("/");
        actionName = new TransitionActionTextFigure("Action", this.getTransitionEntity()); 
        actionName.setText("Action");
        actionName.setEditable(true);
        //instantiate entity class here - james
        // next and last state to be updated in connect because I need the connectors, to find owners
        
        transitionEntity.setAction(actionName.getText());
        add(eventName);
        add(slash);
        add(actionName);
        setLayouter( new HorizontalLayouter());
        Insets2D.Double insets = new Insets2D.Double(6, 6, 6, 6);
	    eventName.set(LAYOUT_INSETS, insets);
       
	    
	    //tried this layout didn't like it, couldn't get spacing right with three labels- james
        /*setLayouter(new LocatorLayouter());
        LocatorLayouter.LAYOUT_LOCATOR.set(eventName, new RelativeLocator(.5,.5, true));
        LocatorLayouter.LAYOUT_LOCATOR.set(slash, new RelativeLocator(.6,.6,true));
        LocatorLayouter.LAYOUT_LOCATOR.set(actionName, new RelativeLocator(.7,.7,true));*/
        
      
    }
    public TransitionEntity getTransitionEntity() {
		return transitionEntity;
	}
    
    public void setActionName(String newValue) {
        getActionNameFigure().setText(newValue);
    }
    
    public TransitionActionTextFigure getActionNameFigure() {
        return (TransitionActionTextFigure ) ((TextFigure) getChild(2));
    }
	/**
     * Checks if two figures can be connected. Implement this method
     * to constrain the allowed connections between figures.
     */
    @Override
    public boolean canConnect(Connector start, Connector end) {
    	if ((start.getOwner() instanceof StateFigure)
    			&& (end.getOwner() instanceof StateFigure)) {

    		StateFigure sf = (StateFigure) start.getOwner();
    		StateFigure ef = (StateFigure) end.getOwner();

    		// Disallow multiple connections to same dependent
    		if (ef.getPredecessors().contains(sf)) {
    			return false;
    		}
    		if(end.getOwner() instanceof StartStateFigure){
    			return false;
    		}

    		// Disallow cyclic connections
    		//   return !sf.isDependentOf(ef);
    	}

    	//don't allow connections to start state or from end state - james
    	if(end.getOwner() instanceof StartStateFigure){
    		return false;
    	}
    	if(start.getOwner() instanceof EndStateFigure){
    		return false;
    	}
    	if(start.getOwner() instanceof StartStateFigure && end.getOwner() instanceof EndStateFigure){
    		return false;
    	}
    	//check sub / super state connectivity
    	//////////// start is sub state block//////////////////////////////
    	if (start.getOwner() instanceof SubStateFigure)
    	{
    		SubStateFigure sf = (SubStateFigure) start.getOwner();

    		//connecting to another substate (must have same parent)
    		if (end.getOwner() instanceof SubStateFigure){
    			SubStateFigure ef = (SubStateFigure) end.getOwner();
    			if(ef.hasAParent() && !(sf.getParentFigure() == ef.getParentFigure()))
    				return false;
    		}
    		//connecting to a superstate (must be parent superstate) 
    		if (end.getOwner() instanceof SuperStateFigure){
    			SuperStateFigure ef = (SuperStateFigure)end.getOwner();
    			if(!(sf.getParentFigure() == ef)){
    				return false;
    			}
    		}

    		//conncting to normal states (return false)
    		if ( !(end.getOwner() instanceof SubStateFigure) && !(end.getOwner() instanceof SuperStateFigure )){
    			//System.out.println("what the fuck");
    			return false;
    		}
    	}
    	///////////////////////////////////////start is super block////////////////////////////////////////////////
    	if (end.getOwner() instanceof SubStateFigure && start.getOwner() instanceof SuperStateFigure)
    	{
    		//cast as subStateFigure
    		SubStateFigure ef = (SubStateFigure) end.getOwner();
    		SuperStateFigure sf = (SuperStateFigure) start.getOwner();

    		if((ef.hasAParent())){//if sub already has a parent cant connect
    			return false;
    		}

    	}
    	///////////////////////////////other cases block////////////////////////////////////////////////
    	if(!(start.getOwner() instanceof SuperStateFigure) && !(start.getOwner() instanceof SubStateFigure) && end.getOwner() instanceof SubStateFigure){
    		return false;
    	}
    	if(start.getOwner() instanceof StartStateFigure && end.getOwner() instanceof SubStateFigure){
    		return false;
    	}
    	if(start.getOwner() instanceof SubStateFigure && end.getOwner() instanceof EndStateFigure){
    		return false;
    	}
    	//anything else let it happen
    	return true;
    }

    @Override
    public boolean canConnect(Connector start) {
        return (start.getOwner() instanceof StartStateFigure ||(start.getOwner() instanceof StateFigure)  );
    }
   // return (start.getOwner() instanceof StateFigure) || 
    /**
     * Handles the disconnection of a connection.
     * Override this method to handle this event.
     */
    //TODO handle sub / super state disconnect here
    @Override
    protected void handleDisconnect(Connector start, Connector end) {
    	if(end.getOwner() instanceof EndStateFigure){
    		if(end.getOwner() instanceof StateFigure){
    			StateFigure sf = (StateFigure) start.getOwner();
    			sf.removeDependency(this);
    		}
    		if(end.getOwner() instanceof SuperStateFigure){
    			SuperStateFigure sf = (SuperStateFigure) start.getOwner();
    			sf.removeDependency(this);
    		}
    	}
    	if(start.getOwner() instanceof StartStateFigure){
    		if(start.getOwner() instanceof StateFigure){
    			StateFigure ef = (StateFigure) end.getOwner();
    			ef.removeDependency(this);
    		}
    		if(start.getOwner() instanceof SuperStateFigure){
    			SuperStateFigure ef = (SuperStateFigure) end.getOwner();
    			ef.removeDependency(this);
    		}
    	}
    	if(start.getOwner() instanceof SubStateFigure && end.getOwner() instanceof SubStateFigure){
    		SubStateFigure sf = (SubStateFigure) start.getOwner();
    		SubStateFigure ef = (SubStateFigure) end.getOwner();
    		sf.removeDependency(this);
    		ef.removeDependency(this);
    	}
    	if(start.getOwner() instanceof SubStateFigure && end.getOwner() instanceof SuperStateFigure){
    		SubStateFigure sf = (SubStateFigure) start.getOwner();
    		SuperStateFigure ef = (SuperStateFigure) end.getOwner();
    		sf.removeDependency(this);
    		ef.removeDependency(this);
    	}
    	if(start.getOwner() instanceof SuperStateFigure && end.getOwner() instanceof SubStateFigure){
    		SuperStateFigure sf = (SuperStateFigure) start.getOwner();
    		SubStateFigure ef = (SubStateFigure) end.getOwner();
    		sf.removeDependency(this);
    		ef.getStateEntity().setParent(sf.getStateEntity());
    		ef.setParentFigure(sf);
    		ef.removeDependency(this);
    	}
    	else if (start.getOwner() instanceof StateFigure && end.getOwner() instanceof StateFigure){
    		StateFigure sf = (StateFigure) start.getOwner();
    		StateFigure ef = (StateFigure) end.getOwner();
    		sf.removeDependency(this);
    		ef.removeDependency(this);
    	}
    	
    }

    /**
     * Handles the connection of a connection.
     * Override this method to handle this event.
     */
    //TODO handle substate / super state connection
    @Override
    protected void handleConnect(Connector start, Connector end) {
    	if(end.getOwner() instanceof EndStateFigure){
    		 EndStateFigure ef = (EndStateFigure) end.getOwner(); 
    		if(start.getOwner() instanceof StateFigure){
    			StateFigure sf = (StateFigure) start.getOwner();
    			 sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
    	   	      this.getTransitionEntity().setFromState(sf.getStateEntity());
    	   	      this.getTransitionEntity().setToState(ef.getStateEntity());
    	   	      sf.addDependency(this);
    		}
    		else{//else its only possible that it is a superstate
    			StateFigure sf = (SuperStateFigure) start.getOwner();
    			 sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
    	   	      this.getTransitionEntity().setFromState(sf.getStateEntity());
    	   	      this.getTransitionEntity().setToState(ef.getStateEntity());
    	   	      sf.addDependency(this);
    		}
    	}
    	if(start.getOwner() instanceof StartStateFigure){
    		StartStateFigure sf = (StartStateFigure) start.getOwner();
    		if(end.getOwner() instanceof StateFigure){
    		StateFigure ef = (StateFigure) end.getOwner();
            sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
            this.getTransitionEntity().setFromState(sf.getStateEntity());
            this.getTransitionEntity().setToState(ef.getStateEntity());
            ef.addDependency(this);
    		}
    		else{//must be superstate
    			SuperStateFigure ef = (SuperStateFigure) end.getOwner();
                sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
                this.getTransitionEntity().setFromState(sf.getStateEntity());
                this.getTransitionEntity().setToState(ef.getStateEntity());
                ef.addDependency(this);
    		}
    	}
    	if(start.getOwner() instanceof SuperStateFigure && end.getOwner() instanceof SuperStateFigure){
            SuperStateFigure sf = (SuperStateFigure) start.getOwner();
            SuperStateFigure ef = (SuperStateFigure) end.getOwner();
            sf.addDependency(this);
            //store next state and last state in the entity class here - james
            sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
            this.getTransitionEntity().setFromState(sf.getStateEntity());
            this.getTransitionEntity().setToState(ef.getStateEntity());
            ef.addDependency(this);
        }
    	if(start.getOwner() instanceof SubStateFigure && end.getOwner() instanceof SubStateFigure){
            SubStateFigure sf = (SubStateFigure) start.getOwner();
            SubStateFigure ef = (SubStateFigure) end.getOwner();
            sf.addDependency(this);
          
            sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
            this.getTransitionEntity().setFromState(sf.getStateEntity());
            this.getTransitionEntity().setToState(ef.getStateEntity());
            ef.addDependency(this);
            //connecting sub states set  end substates parent
            ef.setParentFigure(sf.getParentFigure());
        }
    	if(start.getOwner() instanceof SuperStateFigure && end.getOwner() instanceof SubStateFigure){
            SuperStateFigure sf = (SuperStateFigure) start.getOwner();
            SubStateFigure ef = (SubStateFigure) end.getOwner();
            sf.addDependency(this);
            //store next state and last state in the entity class here - james
            sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
            ef.setParentFigure(sf);
            this.getTransitionEntity().setFromState(sf.getStateEntity());
            this.getTransitionEntity().setToState(ef.getStateEntity());
            ef.addDependency(this);
        }
    	if(start.getOwner() instanceof SubStateFigure && end.getOwner() instanceof SuperStateFigure){
            SubStateFigure sf = (SubStateFigure) start.getOwner();
            SuperStateFigure ef = (SuperStateFigure) end.getOwner();
            sf.addDependency(this);
            //store next state and last state in the entity class here - james
            sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
            this.getTransitionEntity().setFromState(sf.getStateEntity());
            this.getTransitionEntity().setToState(ef.getStateEntity());
            ef.addDependency(this);
        }
    	else if(start.getOwner() instanceof StateFigure && end.getOwner() instanceof StateFigure){
        StateFigure sf = (StateFigure) start.getOwner();
        StateFigure ef = (StateFigure) end.getOwner();
        sf.addDependency(this);
        //store next state and last state in the entity class here - james
        sf.getStateEntity().addOutgoingTransition(this.getTransitionEntity());
        this.getTransitionEntity().setFromState(sf.getStateEntity());
        this.getTransitionEntity().setToState(ef.getStateEntity());
        ef.addDependency(this);
    	}
    }

    @Override
    public TransitionFigure clone() {
        TransitionFigure that = (TransitionFigure) super.clone();

        return that;
    }

    @Override
    public int getLayer() {
        return 1;
    }

    @Override
    public void removeNotify(Drawing d) {
    	if (getStartFigure() != null && getStartFigure() instanceof StartStateFigure){
    		( (StartStateFigure) getStartFigure()).getStateEntity().removeOutgoingTransition(this.getTransitionEntity());
    	}
        if (getStartFigure() != null && getStartFigure() instanceof StateFigure) {
            ((StateFigure) getStartFigure()).removeDependency(this);
          ( (StateFigure) getStartFigure()).getStateEntity().removeOutgoingTransition(this.getTransitionEntity());
        }
        if (getEndFigure() != null && getEndFigure() instanceof StateFigure) {
            ((StateFigure) getEndFigure()).removeDependency(this);
        }
        super.removeNotify(d);
    }
    
    public void write(DOMOutput out) throws IOException {
       super.write(out);
       out.openElement("text");
       out.writeObject(this.getTransitionEntity().getName());
       out.closeElement();
       out.openElement("action");
       out.writeObject(getTransitionEntity().getAction());
       out.closeElement();
       
    }
    
    public void read(DOMInput in) throws IOException {
      super.read(in);
      
      in.openElement("text");
      String  text = (String)in.readObject();
      eventName.setText(text);
      in.closeElement();
      in.openElement("action");
      String action =(String)in.readObject();
      actionName.setText(action);
      in.closeElement();
    }
}
